import { updateNodeElement } from "../DOM"
import { creareTastQueue, arrified, createStateNode, getTag, getRoot } from "../Misc"

const taskQueue = creareTastQueue()

let subTask = null

let pendingCommit = null

const commitAllWork = fiber => {
  fiber.effects.forEach(item => {
    if (item.tag === 'class_component') {
      item.stateNode.__fiber = fiber
    }
    if (item.effectTag === 'delete') {
      item.parent.stateNode.removeChild(item.stateNode)
    } else if (item.effectTag === 'update') {
      if (item.type === item.alternate.type) {
        updateNodeElement(item.stateNode, item, item.alternate)
      } else {
        item.parent.stateNode.replaceChild(
          item.stateNode,
          item.alternate.stateNode
        )
      }
    } else if (item.effectTag === 'placement') {
      let fiber = item
      let parentFiber = item.parent
      while (parentFiber.tag === 'class_component' || parentFiber.tag === 'function_component') {
        parentFiber = parentFiber.parent
      }
      if (fiber.tag === 'host_component') {
        parentFiber.stateNode.appendChild(fiber.stateNode)
      }
    } 
  });
  // 备份旧的fiber对象
  fiber.stateNode.__rootFiberContainer = fiber

}

const getFirsTask = () => {
  /**
   * 从任务队列中获取任务
   */
  const task = taskQueue.pop()
  /**
   * 返回最外层节点的fiber对象
   * {
      type         节点类型 (元素, 文本, 组件)(具体的类型)
      props        节点属性
      stateNode    节点 DOM 对象 | 组件实例对象
      tag          节点标记 (对具体类型的分类 hostRoot || hostComponent || classComponent || functionComponent)
      effects      数组, 存储需要更改的 fiber 对象
      effectTag    当前 Fiber 要被执行的操作 (新增, 删除, 修改)
      parent       当前 Fiber 的父级 Fiber
      child        当前 Fiber 的子级 Fiber
      sibling      当前 Fiber 的下一个兄弟 Fiber
      alternate    Fiber 备份 fiber 比对时使用
    }
   */
  if (task.form === 'class_component') {
    const root = getRoot(task.instance)
    task.instance.__fiber.partialState = task.partialState
    return {
      props: root.props,
      stateNode: root.stateNode,
      tag: 'host_root',
      effects: [],
      child: null,
      alternate: root
    }
  }
  return {
    props: task.props,
    stateNode: task.dom,
    tag: 'host_root',
    effects: [],
    child: null,
    alternate: task.dom.__rootFiberContainer
  }
}

const reconcileChildren = (fiber, children) => {
  /**
   * children 可能是对象或者数组
   */
  const arrifiedChild = arrified(children)
  let index = 0
  let numberOfElements = arrifiedChild.length
  let element = null
  let newFiber = null
  let preFiber= null
  let alternate = null
  if (fiber.alternate && fiber.alternate.child) {
    alternate = fiber.alternate.child
  }
  while (index < numberOfElements || alternate) {
    element = arrifiedChild[index]
    if (!element && alternate) {
      alternate.effectTag = 'delete'
      fiber.effects.push(alternate)
    } else if (element && alternate) {
       // 设置子级fiber对象
       newFiber= {
        type: element.type,
        props: element.props,
        tag: getTag(element),
        effects: [],
        effectTag: 'update',
        parent: fiber,
        alternate
      }
      if (element.type === alternate.type) { // 相同类型
        newFiber.stateNode = alternate.stateNode
      } else {
        newFiber.stateNode = createStateNode(newFiber)
      }
    } else if (element && !alternate) {
        // 设置子级fiber对象
      newFiber= {
        type: element.type,
        props: element.props,
        tag: getTag(element),
        effects: [],
        effectTag: 'placement',
        parent: fiber,
      }

      newFiber.stateNode = createStateNode(newFiber)
    }
    
    if (index === 0) {
      fiber.child = newFiber
    } else if (element) {
      preFiber.sibling = newFiber
    }

    if (alternate && alternate.sibling) {
      alternate = alternate.sibling
    } else {
      alternate = null
    }
    
    preFiber = newFiber
    index++
  }
}

const executeTask = fiber => {
  if (fiber.tag === 'class_component') {
    if (fiber.stateNode.__fiber && fiber.stateNode.__fiber.partialState) {
      fiber.stateNode.state = {
        ...fiber.stateNode.state,
        ...fiber.stateNode.__fiber.partialState
      }
    }

    reconcileChildren(fiber, fiber.stateNode.render())
  } else if (fiber.tag === 'function_component') {
    reconcileChildren(fiber, fiber.stateNode(fiber.props))
  } else {
    reconcileChildren(fiber, fiber.props.children)
  }
  if (fiber.child) {
    return fiber.child
  }

  let currentExecutelyFiber = fiber

  while(currentExecutelyFiber.parent) {
    currentExecutelyFiber.parent.effects = currentExecutelyFiber.parent.effects.concat(
      currentExecutelyFiber.effects.concat([currentExecutelyFiber])
    )
    if (currentExecutelyFiber.sibling) {
      return currentExecutelyFiber.sibling
    }
    currentExecutelyFiber = currentExecutelyFiber.parent
  }
  pendingCommit = currentExecutelyFiber
}
const workLoop = deadline => {
  if (!subTask) {
    subTask = getFirsTask()
  }
  while (subTask && deadline.timeRemaining() > 1) {
    subTask = executeTask(subTask)
  }
  if (pendingCommit) {
    commitAllWork(pendingCommit)
  }
}

const performTask = deadline => {
  workLoop(deadline)
  if (subTask || !taskQueue.isEmpty()) {
    requestIdleCallback(performTask)
  }
}

export const render = (element, dom) => {
  /**
   * 1. 向任务队列中添加任务
   * 2. 指定浏览器空闲时执行任务
   */
  taskQueue.push({
    dom,
    props: { children: element }
  })
  requestIdleCallback(performTask)
}
export const scheduleUpdate = (instance, partialState) => {
  taskQueue.push({
    form: 'class_component',
    instance,
    partialState
  })
  requestIdleCallback(performTask)
}